#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<conio.h>
#include<fstream>
#include<string>
#include<sstream>
#include<iomanip>
#include<windows.h>
#include<pthread.h>
#include <unistd.h>
using namespace std;
#define MEM_SIZE 1024*1024//总磁盘空间为1M
#define DISK_SIZE 1024//磁盘块大小1K
#define DISK_NUM 1024//磁盘块1K
#define MSD 7//最大子目录数max subdirect
#define FATSIZE DISK_NUM*sizeof(fatItem)//FAT表大小，每块磁盘对应一个fat表
#define USER_ROOT_STARTBLOCK FATSIZE/DISK_SIZE+1//用户根目录起始盘块号
#define USER_ROOT_SIZE sizeof(direct)//用户根目录大小
#define MAX_FILE_SIZE 100//最大文件长度

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

/*文件控制块*/
typedef struct FCB {
	char fileName[20];//文件或目录名
	int type;// 0--文件  1--目录 
	char* content = NULL;//文件内容
	int size;//大小
	int firstDisk;//起始盘块
	int next;//子目录起始盘块号
	int sign;//0--普通目录  1--根目录
	int flag = 0;//文件状态，0--关闭  1--打开
	int flock;//锁，0--未上锁，1--上锁，读写锁，只可读，不可写
	int offset = 0;//默认偏移量为0
}FCB;
/*目录*/
struct direct {
	FCB directItem[MSD + 2];
};
/*文件分配表*/
typedef struct fatItem {
	int item;//存放文件下一个磁盘的指针
	int state;//0-- 空闲  1--被占用
}fatItem, * FAT;

string userLogin = "userfile.txt";//用户目录表，用于记录用户名和密码
string userName, userPassword;//当前用户名和密码
FAT fat;//FAT表，fat是一个字符地址
direct* root;//根目录
direct* curDir;//当前目录
string curPath;//当前路径
string userDat;//当前用磁盘文件
char* fdisk;//虚拟磁盘起始地址

size_t find_nth_newline(string str, size_t n) {
	size_t pos = 0; // 当前找到的换行符的位置
	size_t count = 0; // 找到的换行符数量
	
	// 使用find从字符串的开始处搜索换行符
	while (pos != std::string::npos) {
		pos = str.find('\n', pos);
		if (pos != std::string::npos) {
			count++; // 增加找到的换行符数量
			if (count == n) {
				// 如果找到第n个换行符，返回它的位置
				return pos;
			}
			pos++; // 移动到当前换行符之后，继续搜索
		} else {
			break; // 如果没有找到换行符，退出循环
		}
	}
	return std::string::npos; // 如果没有找到第n个换行符，返回npos
}

size_t find_nth_newline_from_end(string str, size_t n) {
	size_t pos = str.rfind('\n'); // 找到最后一个换行符的位置
	size_t count = 1; // 从 1 开始计数
	
	// 继续查找，直到找到第 n 个换行符或到达字符串开头
	while (count < n && pos != string::npos) {
		// 从当前换行符的前一个字符开始继续查找
		pos = str.rfind('\n', pos - 1);
		if (pos != string::npos) {
			++count; // 找到换行符，计数加 1
		}
	}
	
	// 如果找到了第 n 个换行符，返回它的位置，否则返回 npos
	return (count == n) ? pos : string::npos;
}

void newsave(){
	ofstream fp;
	fp.open(userDat, ios::out | ios::binary);
	if (fp) {
		fp.write(fdisk, MEM_SIZE * sizeof(char));
		fp.close();
		
	}
	else {
		cout << userDat << "打开失败！" << endl;
		fp.close();
		
	}
}

//去两边空格
void strip(string& str, char ch){
	int i = 0;
	while (str[i] == ch)i++;
	int j = str.size() - 1;
	while (str[j] == ch)j--;
	str = str.substr(i, j + 1 - i);
}
//划分用户名和密码
void halfStr(string& userName, string& password, string line){
	int i;
	int len = line.length();
	for (i = 0; i < len; i++)
		if (line[i] == ' ')break;
	userName = line.substr(0, i);
	password = line.substr(i + 1, len);
}
/*输出当前用户名和路径*/
void Shell(){
	//设置用户名和路径的前景色和背景色
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN);
	cout << curPath << ">";//输出用户名和路径
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY| FOREGROUND_RED  |FOREGROUND_GREEN | FOREGROUND_BLUE);
}
/*保存磁盘数据*/
void* save(void*){
	while(1){
		pthread_mutex_lock(&mutex);
		// 等待条件变量信号
		pthread_cond_wait(&cond, &mutex);
		ofstream fp;
		fp.open(userDat, ios::out | ios::binary);
		if (fp) {
			fp.write(fdisk, MEM_SIZE * sizeof(char));
			fp.close();
		}
		else {
			cout << userDat << "打开失败！" << endl;
			fp.close();
		}
		pthread_mutex_unlock(&mutex);
	}
	return NULL;
}
/*用户磁盘初始化*/
void init(string userDat){
	fdisk = new char[MEM_SIZE*sizeof(char)];//申请磁盘空间，返回值为起始地址
	//初始化FAT表
	fat = (FAT)(fdisk + DISK_SIZE);//fat地址
	fat[0].item = -1;fat[0].state = 1;//初始化FAT表
	for (int i = 1; i < USER_ROOT_STARTBLOCK - 1; i++) {
		fat[i].item = i + 1;
		fat[i].state = 1;
	}
	fat[USER_ROOT_STARTBLOCK].item = -1; 
	fat[USER_ROOT_STARTBLOCK].state = 1;//根目录磁盘块号
	//fat其他块初始化
	for (int i = USER_ROOT_STARTBLOCK + 1; i < DISK_NUM; i++) {
		fat[i].item = -1;
		fat[i].state = 0;//未分配
	}
	//根目录初始化
	root = (struct direct*)(fdisk + DISK_SIZE + FATSIZE);//根目录地址
	root->directItem[0].sign = 1;//表示为目录文件
	root->directItem[0].firstDisk = USER_ROOT_STARTBLOCK;//对应的磁盘块
	strcpy(root->directItem[0].fileName , ".");//自己
	root->directItem[0].next = root->directItem[0].firstDisk;
	root->directItem[0].type = 1;
	root->directItem[0].size = USER_ROOT_SIZE; 
	//父目录初始化
	root->directItem[1].sign = 1;
	root->directItem[1].firstDisk = USER_ROOT_STARTBLOCK;
	strcpy(root->directItem[1].fileName, "..");
	root->directItem[1].next = root->directItem[0].firstDisk;
	root->directItem[1].type = 1;
	root->directItem[1].size = USER_ROOT_SIZE;
	//子目录初始化
	for (int i = 2; i < MSD+2; i++) {
		root->directItem[i].sign = 0;
		root->directItem[i].firstDisk = -1;//未分配磁盘
		strcpy(root->directItem[i].fileName,"");
		root->directItem[i].next = -1;//无子目录
		root->directItem[i].type = 0;
		root->directItem[i].size = 0;
	}
//	if (save(NULL))cout << "初始化失败！" << endl;
//	save(NULL);
	newsave();
}
/*读取用户磁盘数据内容*/



void readUserDisk(string userDat){
	fdisk = new char[MEM_SIZE];//申请磁盘大小缓冲区
	ifstream fp;
	fp.open(userDat, ios::in | ios::binary);
	if (fp)
		fp.read(fdisk, MEM_SIZE);
	else
		cout << userDat << "打开失败！" << endl;
	fp.close();
	fat = (FAT)(fdisk + DISK_SIZE);//fat地址
	root = (struct direct*)(fdisk + DISK_SIZE + FATSIZE);//根目录地址
	curDir = root;
	curPath = userName + ":\\";
}
/*释放缓冲区空间*/
void release(){
	delete fdisk;
}
int create(string* str){
	char fName[20]; strcpy(fName, str[1].c_str());
	//检查文件名是否合法
	if (!strcmp(fName, ""))return 0;
	if (str[1].length() >20) {
		cout << "文件名太长！请重新输入！" << endl;
		return 0;
	}
	//找当前目录下是否有文件重名
	for (int pos = 2; pos < MSD + 2; pos++) {
		if (!strcmp(curDir->directItem[pos].fileName,fName)&& curDir->directItem[pos].type == 0) {
			cout << "当前目录下已存在文件重名!" << endl;
			return 0;
		}
	}
	//检查当前目录下空间是否已满
	int i;
	for (i = 2; i < MSD + 2; i++) 
		if (curDir->directItem[i].firstDisk == -1)break;//找到了空的子目录即退出
	if (i >= MSD + 2) {
		cout << "当前目录下空间已满" << endl;
		return 0;
	}
	//检查是否有空闲磁盘块
	int j;
	for (j = USER_ROOT_STARTBLOCK + 1; j < DISK_NUM; j++)//查找fat表
		if (fat[j].state == 0) {
			fat[j].state = 1;
			break;
		}
	if (j >= DISK_NUM) {
		cout << "无空闲盘块！" << endl;
		return 0;
	}
	//文件初始化
	curDir->directItem[i].sign = 0;
	curDir->directItem[i].firstDisk = j;
	strcpy(curDir->directItem[i].fileName, fName);
	curDir->directItem[i].next = j;
	curDir->directItem[i].type = 0;
	curDir->directItem[i].size = 0;
//	curDir->directItem[i].fptr = fdisk + j * DISK_SIZE;//设置起始的读写指针位置
	//	char* first = fdisk + item * DISK_SIZE;//起始磁盘块的物理地址
	curDir->directItem[i].offset = 0;
	return 1;
}
int del(string* str){
	char fName[20];strcpy(fName, str[1].c_str()); 
	//在该目录下找目标文件
	int i, temp;
	for (i = 2; i < MSD + 2; i++)
		if (!strcmp(curDir->directItem[i].fileName, fName) && curDir->directItem[i].type == 0)
			break;
	if (i >= MSD + 2) {
		cout << "找不到该文件！" << endl;
		return 0;
	}
	int item = curDir->directItem[i].firstDisk;//目标文件的起始磁盘块号
	//根据文件分配表依次删除文件所占据的磁盘块
	while (item!=-1)
	{
		temp = fat[item].item;
		fat[item].item = -1;
		fat[item].state = 0;
		item = temp;
	}
	//释放目录项
	curDir->directItem[i].sign = 0;
	curDir->directItem[i].firstDisk = -1;
	strcpy(curDir->directItem[i].fileName, "");
	curDir->directItem[i].next = -1;
	curDir->directItem[i].type = 0;
	curDir->directItem[i].size = 0;
	return 1;
}
int open(string* str){
	char fName[20];strcpy(fName, str[1].c_str());
	//检查该目录下是否有目标文件
	int i, j;
	for (i = 2; i < MSD + 2; i++)
		if (!strcmp(curDir->directItem[i].fileName, fName) && curDir->directItem[i].type == 0)
			break;
	if (i >= MSD + 2) {
		//未找到文件
		return 1;
	}
	curDir->directItem[i].flag = 1;
	//成功打开文件
	return 0;
}
int close(string* str){
	char fName[20];strcpy(fName, str[1].c_str());
	//检查该目录下是否有目标文件
	int i, j;
	for (i = 2; i < MSD + 2; i++)
		if (!strcmp(curDir->directItem[i].fileName, fName) && curDir->directItem[i].type == 0)
			break;
	if (i >= MSD + 2) {
		//文件未找到
		return 1;
	}
	curDir->directItem[i].flag = 0;
	//文件关闭成功
	return 0;
}
void read(string* str, char* buf){
	char fName[20];strcpy(fName, str[1].c_str());
	//检查该目录下是否有目标文件
	int i, j;
	for (i = 2; i < MSD + 2; i++)
		if (!strcmp(curDir->directItem[i].fileName, fName) && curDir->directItem[i].type == 0)
			break;
	if (i >= MSD + 2) {
		cout << "找不到该文件！" << endl;
		return;
	}
	if(curDir->directItem[i].flag == 0){
		cout<<"文件未打开"<<endl;
		return;
	}
	int item = curDir->directItem[i].firstDisk;//目标文件的起始磁盘块号
	int fSize = curDir->directItem[i].size;//目标文件的大小
	int offset = curDir->directItem[i].offset;
	int needDisk = fSize / DISK_SIZE;//占据的磁盘块数量
	int needRes = fSize % DISK_SIZE;//占据最后一块磁盘块的大小
	if (needRes > 0)needDisk += 1;
//	char* first = fdisk + item * DISK_SIZE;//起始磁盘块的物理地址
//	char* first = curDir->directItem[i].fptr;
	char* first = fdisk + item * DISK_SIZE + offset;//读写指针位置，文件起始地址加上偏移量
	//将目录文件内容拷贝到缓冲区中
	if (fSize <= 0) {
		buf[0] = '\0';
		return;
	}
	for (i = 0; i < needDisk; i++) {
		for (j = 0; j < fSize - i * DISK_SIZE; j++) {
			buf[i * DISK_SIZE + j] = first[j];
		}
		if (i == needDisk - 1 && j == fSize - i * DISK_SIZE)
			buf[i * DISK_SIZE + j] = '\0';			
		if (i != needDisk - 1) {
			item = fat[item].item;
			first = fdisk + item * DISK_SIZE;
		}
	}
}//
void write(string* str,char *content,int size){
	char fName[20];
	strcpy(fName, str[1].c_str());//第二个输入
	//在当前目录下查找目标文件
	int i, j;
	for (i = 2; i < MSD + 2; i++)
		if ((strcmp(curDir->directItem[i].fileName, fName) == 0) && curDir->directItem[i].type == 0)
			break;
	if (i >= MSD + 2) {
		cout << "找不到该文件！" << endl;
		return;
	}
	
	
	
	int cur = i;//当前目录项的下标
	int fSize = curDir->directItem[cur].size;//目标文件大小
	int item = curDir->directItem[cur].firstDisk;//目标文件的起始磁盘块号
	int offset = curDir->directItem[cur].offset;
	while (fat[item].item != -1)item = fat[item].item;//计算保存该文件的最后一块盘块号
//	char* first = fdisk + item * DISK_SIZE + fSize % DISK_SIZE;//计算该文件的末地址
//	char* first = curDir->directItem[cur].fptr;
	
	char* first = fdisk + item * DISK_SIZE + offset;//读写指针位置，文件起始地址加上偏移量
	//如果盘块剩余部分够写，则直接写入剩余部分
	if (DISK_SIZE - fSize % DISK_SIZE > size) {
		strcpy(first, content);
		if(curDir->directItem[cur].firstDisk == -1){
			curDir->directItem[cur].size += size;
		}
		else{
//			curDir->directItem[cur].size = max(size + offset, curDir->directItem[cur].size);
			curDir->directItem[cur].size = size + offset;
		}
//		curDir->directItem[cur].size = max(curDir->directItem[cur].size, size);
//		curDir->directItem[cur].size = max(size + offset, curDir->directItem[cur].size);
//		if(size + offset > curDir->directItem[cur].size){
//		}
	}
	//如果盘块剩余部分不够写，则找到空闲磁盘块写入
	else {
		//先将起始磁盘剩余部分写完
		for (j = 0; j < DISK_SIZE - fSize % DISK_SIZE; j++) {
			first[j] = content[j];
		}
		int res_size = size - (DISK_SIZE - fSize % DISK_SIZE);//剩余要写的内容大小
		int needDisk = res_size / DISK_SIZE;//占据的磁盘块数量
		int needRes = res_size % DISK_SIZE;//占据最后一块磁盘块的大小
		if (needDisk > 0)needRes += 1;
		for (j = 0; j < needDisk; j++) {
			for (i = USER_ROOT_STARTBLOCK + 1; i < DISK_NUM; i++)
				if (fat[i].state == 0) break;
			if (i >= DISK_NUM) {
				cout << "磁盘已被分配完！" << endl;
				return;
			}
			first = fdisk + i * DISK_SIZE;//空闲磁盘起始盘物理地址
			//当写到最后一块磁盘，则只写剩余部分内容
			if (j == needDisk - 1) {
				for (int k = 0; k < size - (DISK_SIZE - fSize % DISK_SIZE - j * DISK_SIZE); k++)
					first[k] = content[k];
			}
			else {
				for (int k = 0; k < DISK_SIZE; k++)
					first[k] = content[k];
			}
			//修改文件分配表内容
			fat[item].item = i;
			fat[i].state = 1;
			fat[i].item = -1;
		}
		if(curDir->directItem[cur].firstDisk == -1){
			curDir->directItem[cur].size += size;
		}
		else{
//			curDir->directItem[cur].size = max(size + offset, curDir->directItem[cur].size);
			curDir->directItem[cur].size = size + offset;
		}
	}
}
void cd(string* str){
	char fName[20]; 
	strcpy(fName, str[1].c_str()); 
	string objPath = str[1];//目标路径
	if (objPath[objPath.size() - 1] != '\\')
		objPath += "\\";
	int start = -1; 
	int end = 0;//以\为分割，每段起始下标和结束下标
	int i, j, len = objPath.length();
	direct* tempDir = curDir;
	string oldPath = curPath;//保存切换前的路径
	string temp;
	if (objPath[0] == '\\') {
		tempDir = root;
		curPath = userName + ":\\";
		for (i = 1; i<len; i++) {
			//如果目标路径以\开头，则从根目录开始查询
			
			if (start == -1)
				start = i;
			if (objPath[i] == '\\') {
				end = i;
				temp = objPath.substr(start, end-start);
				//检查目录是否存在
				for (j = 0; j < MSD + 2; j++)
					if (!strcmp(tempDir->directItem[j].fileName, temp.c_str()) && tempDir->directItem[j].type == 1)
						break;
				if (j >= MSD + 2) {
					curPath = oldPath;
					cout << "找不到该目录！" << endl;
					return;
				}
				//如果目标路径为".."，则返回上一级
				if (temp=="..") {
					if (tempDir->directItem[j - 1].sign != 1) {
						int pos = curPath.rfind('\\', curPath.length() - 2);
						curPath = curPath.substr(0, pos + 1);
					}
				}
				//如果目标路径为"."，则指向当前目录
				else {
					if (temp != ".") 		
						curPath = curPath + objPath.substr(start,end-start) + "\\";
				}
				start = -1;		
				tempDir = (direct*)(fdisk + tempDir->directItem[j].firstDisk * DISK_SIZE);			
			}
		}
//		continue;
	}
	else{
		for (i = 0; i<len; i++) {
			//如果目标路径以\开头，则从根目录开始查询
			
			if (start == -1)
				start = i;
			if (objPath[i] == '\\') {
				end = i;
				temp = objPath.substr(start, end-start);
				//检查目录是否存在
				for (j = 0; j < MSD + 2; j++)
					if (!strcmp(tempDir->directItem[j].fileName, temp.c_str()) && tempDir->directItem[j].type == 1)
						break;
				if (j >= MSD + 2) {
					curPath = oldPath;
					cout << "找不到该目录！" << endl;
					return;
				}
				//如果目标路径为".."，则返回上一级
				if (temp=="..") {
					if (tempDir->directItem[j - 1].sign != 1) {
						int pos = curPath.rfind('\\', curPath.length() - 2);
						curPath = curPath.substr(0, pos + 1);
					}
				}
				//如果目标路径为"."，则指向当前目录
				else {
					if (temp != ".") 		
						curPath = curPath + objPath.substr(start,end-start) + "\\";
				}
				start = -1;		
				tempDir = (direct*)(fdisk + tempDir->directItem[j].firstDisk * DISK_SIZE);			
			}
		}
	}
	
	curDir = tempDir;
}
void copy(string* str){	
	char source[20]; 
	strcpy(source, str[1].c_str()); 
	string s_source = str[1];//原文件或目录
	char obj[20]; 
	strcpy(obj, str[2].c_str()); 
	string s_obj = str[2];//目标文件或目录
	//检查原文件或目录是否存在并合法
	if (s_source == "" || s_obj == "") {
		cout << "输入错误！" << endl;
		return;
	}
	int i, j;
	for (i = 2; i < MSD + 2; i++) {
		if (!strcmp(curDir->directItem[i].fileName, source)) 
			break;
	}
	if (i >= MSD + 2) {
		cout << "找不到目录文件！" << endl;
		return;
	}
	
	char* content = new char[MAX_FILE_SIZE];
	//move的第二个参数即是源文件名，而read第二个参数也是文件名
	read(str, content);//原文件内容被保存在content中
	string dirstr[3],filestr[3];
	dirstr[0] = " ";
	dirstr[1] = str[2];//str[2]为move的第三个参数
	cd(dirstr);
	create(str);
	open(str);
	write(str,content,strlen(content));
	close(str);
	string cdstr[2];
	cdstr[0] = "";
	cdstr[1] = "..";
	cd(cdstr);//切换目录
	return;
}
void move(string* str){	
	char source[20]; 
	strcpy(source, str[1].c_str()); 
	string s_source = str[1];//原文件或目录
	char obj[20]; 
	strcpy(obj, str[2].c_str()); 
	string s_obj = str[2];//目标文件或目录
	//检查原文件或目录是否存在并合法
	if (s_source == "" || s_obj == "") {
		cout << "输入错误！" << endl;
		return;
	}
	int i, j;
	for (i = 2; i < MSD + 2; i++) {
		if (!strcmp(curDir->directItem[i].fileName, source)) 
			break;
	}
	if (i >= MSD + 2) {
		cout << "找不到目录文件！" << endl;
		return;
	}
	
	char* content = new char[MAX_FILE_SIZE];
	//move的第二个参数即是源文件名，而read第二个参数也是文件名
	read(str, content);//原文件内容被保存在content中
	del(str);//删除在当前的该文件
	string dirstr[3],filestr[3];
	dirstr[0] = " ";
	dirstr[1] = str[2];//str[2]为move的第三个参数
	cd(dirstr);
	create(str);
	open(str);
	write(str,content,strlen(content));
	close(str);
	string cdstr[2];
	cdstr[0] = "";
	cdstr[1] = "..";
	cd(cdstr);//切换目录
	return;
}
void dir(){
	cout << fixed << left << setw(20) << "文件名" << setw(10) << "类型" << setw(10) << "大小</B>" << setw(10) << "起始磁盘块号" << endl;
	for (int i = 2; i < MSD + 2; i++) {
		if (curDir->directItem[i].firstDisk != -1) {
			cout <<fixed<< setw(20) << curDir->directItem[i].fileName;
			if (curDir->directItem[i].type == 0) {//显示文件
				cout << fixed << setw(10) << " " << setw(10) << curDir->directItem[i].size;
			}
			else {//显示目录
				cout << fixed << setw(10) << "<DIR>" << setw(10) << " ";
			}
			cout << setw(10) << curDir->directItem[i].firstDisk << endl;
		}
	}
}
int mkdir(string* str){
	char fName[20]; strcpy(fName, str[1].c_str());
	//检查目录名是否合法
	if (!strcmp(fName, ""))return 0;
	if (str[1].length() > 10) {
		cout << "目录名太长！请重新输入！" << endl;
		return 0;
	}
	if (!strcmp(fName, ".") || !strcmp(fName, "..")) {
		cout << "目录名称不合法！" << endl;
		return 0;
	}
	//找当前目录下是否有目录重名
	for (int pos = 2; pos < MSD + 2; pos++) {
		if (!strcmp(curDir->directItem[pos].fileName, fName)&&curDir->directItem[pos].type==1) {
			cout << "当前目录下已存在目录重名!" << endl;
			return 0;
		}
	}
	//检查当前目录下空间是否已满
	int i;
	for (i = 2; i < MSD + 2; i++)
		if (curDir->directItem[i].firstDisk == -1)break;
	if (i >= MSD + 2) {
		cout << "当前目录下空间已满" << endl; 
		return 0;
	}
	//检查是否有空闲磁盘块
	int j;
	for (j = USER_ROOT_STARTBLOCK + 1; j < DISK_NUM; j++)
		if (fat[j].state == 0) {
			fat[j].state = 1;
			break;
		}
	if (j >= DISK_NUM) { 
		cout << "无空闲盘块！" << endl;
		return 0;
	}
	//创建目录初始化
	curDir->directItem[i].sign = 0;
	curDir->directItem[i].firstDisk = j;
	strcpy(curDir->directItem[i].fileName, fName);
	curDir->directItem[i].next = j;
	curDir->directItem[i].type = 1;
	curDir->directItem[i].size = USER_ROOT_SIZE;
	direct* cur_mkdir = (direct*)(fdisk + curDir->directItem[i].firstDisk * DISK_SIZE);//创建目录的物理地址
	//指向当前目录的目录项
	cur_mkdir->directItem[0].sign = 0;
	cur_mkdir->directItem[0].firstDisk = curDir->directItem[i].firstDisk;
	strcpy(cur_mkdir->directItem[0].fileName, ".");
	cur_mkdir->directItem[0].next = cur_mkdir->directItem[0].firstDisk;
	cur_mkdir->directItem[0].type = 1;
	cur_mkdir->directItem[0].size = USER_ROOT_SIZE;
	//指向上一级目录的目录项
	cur_mkdir->directItem[1].sign = curDir->directItem[0].sign;
	cur_mkdir->directItem[1].firstDisk = curDir->directItem[0].firstDisk;
	strcpy(cur_mkdir->directItem[1].fileName, "..");
	cur_mkdir->directItem[1].next = cur_mkdir->directItem[1].firstDisk;
	cur_mkdir->directItem[1].type = 1;
	cur_mkdir->directItem[1].size = USER_ROOT_SIZE;
	//子目录初始化
	for(int i = 2; i < MSD + 2; i++) {
		cur_mkdir->directItem[i].sign = 0;
		cur_mkdir->directItem[i].firstDisk = -1;
		strcpy(cur_mkdir->directItem[i].fileName, "");
		cur_mkdir->directItem[i].next = -1;
		cur_mkdir->directItem[i].type = 0;
		cur_mkdir->directItem[i].size = 0;
	}
	return 1;
}
int rmdir(string* str){
	char fName[20];strcpy(fName, str[1].c_str()); 
	//在当前目录下查询目标目录
	int i,j; direct* tempDir = curDir;
	for(i=2;i<MSD+2;i++)
		if (!strcmp(tempDir->directItem[i].fileName, fName) && tempDir->directItem[i].type == 1)
			break;
	if (i >= MSD + 2) {
		cout << "找不到该目录！" << endl;
		return 0;
	}
	//检查是否有子目录或文件
	tempDir = (direct*)(fdisk + tempDir->directItem[i].next * DISK_SIZE);
	for (j = 2; j < MSD + 2; j++) {
		if (tempDir->directItem[j].next != -1) {
			cout << "删除失败！该目录下有子目录或文件!" << endl;
			return 0;
		}		
	}
	fat[curDir->directItem[i].firstDisk].state = 0;//修改文件分配表
	//修改目录项
	curDir->directItem[i].sign = 0;
	curDir->directItem[i].firstDisk = -1;
	strcpy(curDir->directItem[i].fileName, "");
	curDir->directItem[i].next = -1;
	curDir->directItem[i].type = 0;
	curDir->directItem[i].size = 0;
	return 1;
}
void flock(string* str){
	char fName[20];strcpy(fName, str[1].c_str());
	//检查该目录下是否有目标文件
	int i, j;
	for (i = 2; i < MSD + 2; i++)
		if (!strcmp(curDir->directItem[i].fileName, fName) && curDir->directItem[i].type == 0)
			break;
	if (i >= MSD + 2) {
		cout << "找不到该文件！" << endl;
		return;
	}
	if(str[2] == "lock"){
		curDir->directItem[i].flock = 1;
		cout <<"文件已经上锁"<<endl;
	}
	else if(str[2] == "unlock"){
		curDir->directItem[i].flock = 0;
		cout <<"文件已经解锁"<<endl;
	}
	else{
		cout<<"error"<<endl;
	}
	
	
	return;
}
void fromheadread(string* str, char* buf){
	char fName[20];strcpy(fName, str[1].c_str());
	//检查该目录下是否有目标文件
	int i, j;
	for (i = 2; i < MSD + 2; i++)
		if (!strcmp(curDir->directItem[i].fileName, fName) && curDir->directItem[i].type == 0)
			break;
	if (i >= MSD + 2) {
		cout << "找不到该文件！" << endl;
		return;
	}
	if(curDir->directItem[i].flag == 0){
		cout<<"文件未打开"<<endl;
		return;
	}
	int item = curDir->directItem[i].firstDisk;//目标文件的起始磁盘块号
	int fSize = curDir->directItem[i].size;//目标文件的大小
	int offset = curDir->directItem[i].offset;
	int needDisk = fSize / DISK_SIZE;//占据的磁盘块数量
	int needRes = fSize % DISK_SIZE;//占据最后一块磁盘块的大小
	if (needRes > 0)needDisk += 1;
	char* first = fdisk + item * DISK_SIZE;//起始磁盘块的物理地址
//	char* first = curDir->directItem[i].fptr;
//	char* first = fdisk + item * DISK_SIZE + offset;//读写指针位置，文件起始地址加上偏移量
	//将目录文件内容拷贝到缓冲区中
	if (fSize <= 0) {
		buf[0] = '\0';
		return;
	}
	for (i = 0; i < needDisk; i++) {
		for (j = 0; j < fSize - i * DISK_SIZE; j++) {
			buf[i * DISK_SIZE + j] = first[j];
		}
		if (i == needDisk - 1 && j == fSize - i * DISK_SIZE)
			buf[i * DISK_SIZE + j] = '\0';			
		if (i != needDisk - 1) {
			item = fat[item].item;
			first = fdisk + item * DISK_SIZE;
		}
	}
}//
void head(string* str){
	char* buf = new char[MAX_FILE_SIZE];//设置缓冲区
	buf[0] = '\0';
	fromheadread(str, buf);
	string content(buf);
	int num;
	try {
		// Attempt to convert the third character to an integer
		num = stoi(str[2]);;
	} catch (const invalid_argument& e) {
		cerr << "Invalid argument: " << e.what() << endl;
		return;;
	} catch (const out_of_range& e) {
		cerr << "Out of range: " << e.what() << endl;
		return;
	} catch (const exception& e) {
		cerr << "Unexpected error: " << e.what() << endl;
		return;
	}
	int pos = find_nth_newline(content,num);
	cout<<content.substr(0,pos)<<endl;
	delete[] buf;
}
void tail(string* str){
	char* buf = new char[MAX_FILE_SIZE];//设置缓冲区
	buf[0] = '\0';
	fromheadread(str, buf);
	string content(buf);
	int num;
	try {
		// Attempt to convert the third character to an integer
		num = stoi(str[2]);;
	} catch (const invalid_argument& e) {
		cerr << "Invalid argument: " << e.what() << endl;
		return;
	} catch (const out_of_range& e) {
		cerr << "Out of range: " << e.what() << endl;
		return;
	} catch (const exception& e) {
		cerr << "Unexpected error: " << e.what() << endl;
		return;
	}
	int pos = find_nth_newline_from_end(content,num);
	cout<<content.substr(pos + 1)<<endl;
	delete[] buf;
}
void lseek(string* str){
	char fName[20];strcpy(fName, str[1].c_str());
	//检查该目录下是否有目标文件
	int i, j;
	for (i = 2; i < MSD + 2; i++)
		if (!strcmp(curDir->directItem[i].fileName, fName) && curDir->directItem[i].type == 0)
			break;
	if (i >= MSD + 2) {
		//未找到文件
		cout<<"该目录下无该文件"<<endl;
		return;
	}
	int offset;
	try {
		// Attempt to convert the third character to an integer
		offset = stoi(str[2]);;
	} catch (const invalid_argument& e) {
		cerr << "Invalid argument: " << e.what() << endl;
		return;
	} catch (const out_of_range& e) {
		cerr << "Out of range: " << e.what() << endl;
		return;
	} catch (const exception& e) {
		cerr << "Unexpected error: " << e.what() << endl;
		return;
	}
	cout<<"lseek操作之前的偏移量为"<<curDir->directItem[i].offset<<endl;
	curDir->directItem[i].offset += offset;//文件读写指针偏移量，默认为0
//	curDir->directItem[i].fptr += offset;//指针的位置
	cout<<"lseek操作后的偏移量为"<<curDir->directItem[i].offset<<endl;
	cout<<"lseekl操作成功！"<<endl;
	//成功打开文件
	return;
}
void import(string* str){
	string filePath = str[1];
	char* content = new char[MAX_FILE_SIZE];//设置缓冲区
	fstream fp;
	fp.open(filePath, ios::in);
	string buf;
	if (fp) {
		while (fp) {
			buf.push_back(fp.get());
		}
		strcpy(content,buf.c_str());
		fp.close();
		int pos = filePath.rfind('/', filePath.length() - 1);
		string obj = filePath.substr(pos+1, filePath.length() - pos-1);
		string newStr[2]; newStr[0] = "create"; newStr[1] = obj;
		string cdstr[3];
		cdstr[0] = "cd";
		cdstr[1] = str[2];//import的第三个参数是路径，而cd的第二个参数是路径
		cd(cdstr);//切到子目录中
		if(create(newStr))//读取本地文件内容并创建文件写入
			write(newStr, content, strlen(content));
		delete[] content;
		cout << "导入文件成功" << endl;
		cdstr[1] = "..";
		cd(cdstr);//切回父目录
	}
	else {
		cout << "打开本地文件失败！" << endl;
	}
}
void Export(string*str){
	string source = str[1], filePath = str[2];
	char* content = new char[MAX_FILE_SIZE];//设置缓冲区
	content[0] = '\0';
	read(str, content);//读取文件内容
	filePath += source;
	fstream file(filePath, ios::out);//打开文件
//	fp.open(filePath, ios::out);
	if (file) {
		file << content;
		cout << "导出文件成功！" << endl;
	}
	else {
		cout << "导出文件失败" << endl;
	}
	delete[] content;
}
void help() {	
	cout << fixed << left;
	cout << "********************  帮助  ********************" << endl << endl;
	cout << setw(40) << "create 文件名" << setw(10) << "创建文件" << endl;
	cout << setw(40) << "delete 文件名" << setw(10) << "删除文件" << endl;
	cout << setw(40) << "open 文件名" << setw(10) << "打开文件" << endl;
	cout << setw(40) << "close 文件名" << setw(10) << "关闭文件" << endl;
	cout << setw(40) << "read 文件名" << setw(10) << "显示文件内容" << endl;
	cout << setw(40) << "write 文件名" << setw(10) << "写入内容" << endl;
	cout << setw(40) << "move 源文件 目标目录" << setw(10) << "移动文件" << endl;
	cout << setw(40) << "copy 源文件 目标文件" << setw(10) << "复制文件" << endl;
	cout << setw(40) << "flock 文件名 lock/unlock" << setw(10) << "复制文件" << endl;
	cout << setw(40) << "head 文件名 n" << setw(10) << "显示文件前n行" << endl;
	cout << setw(40) << "tail 文件名 n" << setw(10) << "显示文件尾n行" << endl;
	cout << setw(40) << "cd 路径" << setw(10) << "切换目录" << endl;
	cout << setw(40) << "dir" << setw(10) << "显示当前目录下所有子目录和子文件" << endl;
	cout << setw(40) << "mkdir 目录名" << setw(10) << "创建目录" << endl;
	cout << setw(40) << "rmdir 目录名" << setw(10) << "删除目录" << endl;
	cout << setw(40) << "import 本地文件路径" << setw(10) << "导入文件" << endl;
	cout << setw(40) << "export 文件名 本地文件路径" << setw(10) << "导出文件" << endl;
	cout << setw(40) << "save" << setw(10) << "保存" << endl;
	cout << setw(40) << "help" << setw(10) << "帮助文档" << endl;
	cout << setw(40) << "clear" << setw(10) << "清屏" << endl;
	cout << setw(40) << "exit" << setw(10) << "退出" << endl << endl;}
void* menu(void*){ 
	system("cls");getchar();
	//如果没有找到磁盘数据文件，则进行初始化
	fstream fp;
	userDat = userName + ".dat";//用户数据
	userDat = userName;
	fp.open(userDat,ios::in|ios::binary);//用户文件不存在，说明是刚刚注册
	if (!fp) {
		init(userDat);//文件不存在，初始化
	}
	fp.close();
	readUserDisk(userDat);
	direct* tempDir = curDir;
	string oldPath = curPath;//保存切换前的路径

	while (true)
	{
		readUserDisk(userDat);
		curDir = tempDir;
		curPath = oldPath;
		string cdstr[2];
		
		int pos = oldPath.find(':');
		
		cdstr[0] = "cd";
		cdstr[1] = oldPath.substr(pos + 1);
		
		cd(cdstr);
		Shell();
		//以空格为界线，读取命令,并用stringstream流分割命令
		string cmd; 
		getline(cin, cmd); 
		stringstream stream; 
		stream.str(cmd);
		string str[5];
		for (int i = 0; stream >> str[i]; i++);//得到多个输入
		//命令菜单选项
		
		if(str[0] == "check"){
			continue;
		}
		
		pthread_mutex_lock(&mutex);
		
		if (str[0] == "exit") {
			newsave();
			exit(0);
		}
		else if (str[0] == "create") {
			
			if (create(str)){
				cout << "文件创建成功！" << endl;
//				save(NULL);
			}
		}
		else if (str[0] == "delete") {
			if (del(str)){
//				save(NULL);
				cout << str[1] << "删除成功！" << endl;
			}
			
		}
		else if (str[0] == "open") {
			if(open(str) == 0){
				cout<<"文件打开成功"<<endl;
//				save(NULL);
			}
			else{
				cout<<"该目录不存在该文件"<<endl;
			}
		}
		else if (str[0] == "close") {
			if(close(str) == 0){
				cout<<"文件关闭成功"<<endl;
//				save(NULL);
			}
			else{
				cout<<"该目录不存在该文件"<<endl;
			}
		}
		else if (str[0] == "read") {
			char* buf = new char[MAX_FILE_SIZE];//设置缓冲区
			buf[0] = '\0';
			read(str, buf);	
			if(strlen(buf)) {
				cout << buf << endl;
				delete[] buf;
			}
		}
		else if (str[0] == "write") {
			//检查当前目录下是否有目标文件
			int i;
			for (i = 2; i < MSD + 2; i++)
				if (!strcmp(curDir->directItem[i].fileName, str[1].c_str()) && curDir->directItem[i].type == 0)//且必须是文件类型，而不是目录
					break;
			if (i >= MSD + 2) {
				cout << "找不到该文件！" << endl;
				continue;
			}
			
			if(curDir->directItem[i].flag == 0){
				cout<<"该文件未打开！"<<endl;
			}
			
			else if(curDir->directItem[i].flock == 1){
				cout<<"该文件已经上锁，只可读，不可写"<<endl;
			}
			
			else{
				//输入写入内容，并以#号结束
				char ch;
				char content[MAX_FILE_SIZE];//设置缓冲区
				content[0] = '\0';
				int size = 0;
				cout << "请输入文件内容，并以'#'为结束标志" << endl;
				while (1)
				{
					ch = getchar();
					if (ch == '#')break;
					if (size >= MAX_FILE_SIZE) { 
						cout << "输入文件内容过长！" << endl;
						break;
					}
					content[size] = ch;
					size++;
				}
				//content中为文件内容
				if (size >= MAX_FILE_SIZE) continue;
				getchar();//缓冲区的上一个换车
				write(str,content,size);
//			save(NULL);
			}
			
		}
		else if (str[0] == "move") {
			move(str);
//			save(NULL);
		}
		else if (str[0] == "copy"){
			copy(str);
//			save(NULL);
		}	
		else if (str[0] == "flock") {
			flock(str);
//			save(NULL);
		}
		else if (str[0] == "head") {
			head(str);
		}
		else if (str[0] == "tail") {
			tail(str);
		}
		else if (str[0] == "lseek") {
			lseek(str);
//			save(NULL);
		}
		else if(str[0]  =="cd"){
			cd(str);
		}
		else if (str[0] == "dir") {
			dir();
		}	
		else if (str[0] =="mkdir") {
			if(mkdir(str)){
				cout << str[1] << "创建成功！" << endl;
//				save(NULL);
			}
		}
		else if (str[0] == "rmdir") {
			if (rmdir(str)){
				cout << str[1] << "删除成功！" << endl;			
//				save(NULL);
			}
		}
		else if (str[0] == "import") {
			import(str);
//			save(NULL);
		}
		else if (str[0] == "export") {
			Export(str);
//			save(NULL);
		}		
		else if(str[0] == "save"){
//			save(NULL);
		}
		else if (str[0] == "clear") {
			system("cls");
		}
		else if (str[0] == "help") {
			help();
		}
		else {
			cout << "找不到该命令！请重新输入" << endl;
		}
		tempDir = curDir;
		oldPath = curPath;//保存切换前的路径
		
		pthread_cond_signal(&cond); // 通知另一个线程已准备好
		pthread_mutex_unlock(&mutex);
		sleep(1);//让出CPU
	}
	release();
}
int Login(){
	//创建用户目录表
	fstream fp;
	fp.open(userLogin, ios::in);
	if (!fp) {
		fp.close();
		fp.open(userLogin, ios::out);
		fp.close();
	}
	int successFlag = 0;//标记是否终止登录
	while (!successFlag)
	{
		int haveUser = 0;//标记是否存在该用户
		//验证用户名
		string inputName;
		cout << "用户名:"; cin >> inputName; strip(inputName, ' ');//输入并处理用户名
		ifstream fp;
		fp.open(userLogin);
		if (fp) {
			string userLine;
			while (getline(fp, userLine)) {
				string name, password;
				halfStr(name, password, userLine);
				if (name == inputName) {
					haveUser = 1;//标记确实有该用户
					userName = name;
					userPassword = password;
				}
			}
			fp.close();
		}
		else {
			cout << userLogin << "打开错误！" << endl;
			return 1;
		}
		
		//如果找到了用户名，则输入密码
		if (haveUser) {
			int flag = 1;//标记是否需要重新出入密码
			int times = 0;//输入密码的次数，如果输入错误大于3次，则终止登录
			while (flag)
			{
				string inputPassword;
				cout << "密码:"; cin >> inputPassword; strip(inputPassword, ' ');
				//如果密码输入正确！
				if (inputPassword == userPassword) {
					flag = 0;
					successFlag = 1;//成功登录
					return 0;
				}
				//密码输入错误
				else{
//					times++;
//					if(times<3) {//选择是否重新输入密码
//						cout << "输入密码错误！" << endl << "是否重新输入（y/n）?:";
//						int again = 1;
//						while (again)
//						{
//							string choice; cin >> choice; strip(choice, ' ');
//							if (choice == "y" || choice == "Y")
//								again = 0;
//							else if (choice == "n" || choice == "N"){
//								flag = 0;
//								again = 0;
//								return 1;
//							}
//							else
//								cout << "您的输入有误！请重新输入（y/n）:";
//						}
//					}else{//密码输入错误达到三次则直接退出
//						cout << "输入密码错误已达到3次！" << endl;
//						flag = 0;
//						return 1;
//					}
					return 1;
				}
			}
		} else{//如果没有找到用户名，报错并请用户选择是否重新输入		
			int again = 1;
			cout << "抱歉没有找到该用户！" << endl << "是否重新输入（y/n）?" << endl;
			while (again)
			{
				string choice; cin >> choice; strip(choice, ' ');
				if (choice == "y" || choice == "Y") 
					again = 0;
				else if (choice == "n" || choice == "N"){
					again = 0;
					return 1;
				}
				else
					cout << "您的输入有误！请重新输入（y/n）:";
			}
		}
	}
	return 1;
}

void Register(){
	//创建用户目录表
	fstream fp;
	fp.open(userLogin, ios::in); 
	if(!fp){
		fp.close();
		fp.open(userLogin, ios::out);
		fp.close();
	}
	int flag = 1;//标记是否终止注册
	while(flag)
	{
		string inputName, password, password2;//用户名，密码，确认密码
		int used = 0;//标记用户名是否已被使用过
		
		//验证用户名
		cout << "请输入注册用户名：";cin >> inputName;	
		ifstream fp;
		fp.open(userLogin);
		if (fp) {
			//从文件中按行读取用户信息，并根据空格划分用户名和密码
			string userLine;
			while (getline(fp, userLine)) {
				string name, password;
				halfStr(name, password, userLine);
				if (name == inputName) {
					used = 1;//标记已存在该用户
				}
			}
			fp.close();
		}
		else {
			cout << userLogin << "打开错误！" << endl;
			return;
		}
		
		//验证密码
		if (!used) {
			cout << "请输入密码：";cin >> password;
//			cout << "请再次输入密码：";cin >> password2;
			//如果两次输入密码都有效且一致，则保存用户名和密码，并提示注册成功
//			if (password == password2) {
				fstream fp;
				fp.open(userLogin, ios::app);
				if (fp) {
					fp<< inputName << " " << password<<endl;
					fp.close();
					cout << "注册成功！" << endl;
				}
				else {
					cout << userLogin << "打开错误！" << endl;
					return;
				}
				flag = 0;
//			}
			//如果两次输入密码不一致，则提示是否重新输入
//			else {
//				int again = 1;
//				cout << "两次密码输入不一致！" << endl << "是否重新输入（y/n）?:";
//				while (again)
//				{
//					string choice; cin >> choice; strip(choice, ' ');
//					if (choice == "y" || choice == "Y") {
//						again = 0;
//					}
//					else if (choice == "n" || choice == "N")
//					{
//						again = 0;
//						return;
//					}
//					else {
//						cout << "您的输入有误！请重新输入（y/n）:";
//					}
//				}
//			}
		}
		//如果用户名已被使用，则提示是否重新输入
		else
		{
			int again = 1;
			cout << "用户名已存在！" << endl << "是否重新输入（y/n）?" << endl;
			while (again)
			{
				string choice; cin >> choice; strip(choice, ' ');
				if (choice == "y" || choice == "Y") {
					again = 0;
				}
				else if (choice == "n" || choice == "N")
				{
					again = 0;
					return;
				}
				else {
					cout << "您的输入有误！请重新输入（y/n）:";
				}
			}
		}		
	}
}
int main()
{
	while (true)
	{
		int flag = 1;
		cout << "	1、登录		2、注册		0、退出	" << endl << endl;
		cout << "请输入：";
		int choice; cin >> choice;
		switch (choice)
		{
			case 1:{
				flag = Login();
				break;
			}
			case 2:Register(); getchar(); break;
			case 0:return 0;
			default:cout << "您的输入有误！请重新输入！" << endl;
			break;
		}
		if(flag == 0){
			break;//退出循环
		}
	
	}
	pthread_t t1,t2;
	pthread_create(&t1, NULL, menu, NULL);
	pthread_create(&t2, NULL, save, NULL);
	
	// 等待线程结束
	pthread_join(t1, NULL);
	pthread_join(t2, NULL);
	
	menu(NULL);
}

